//import { cc.vv.eventCustom } from "./../../lib/cc.vv.eventCustom";

export class HotUpdate {
  errorCode = {
    NEED_UPDATE: 0, //需要热更
    NEED_INSTALL: 1, //需要重新下载新版本
    ERROR_NO_LOCAL_MANIFEST: 2, //本地没有配置文件
    FAIL_DOWMLOAD_MANIFEST: 3, //下载配置失败
    ALREADY_UP_TO_DATE: 4, //已经更新
    UPDATE_PROGRESSION: 5, // 更新中
    UPDATE_FINISHED: 6, //更新完成
    ERROR_UPDATING: 7, //下载失败
    UPDATE_FAILED: 8, //更新失败
    ERROR_DECOMPRESS: 9, //解压失败
    ERROR_OTHER: 10 //其它
  };
  _storagePath = "";
  file_version = "version.manifest";
  file_project = "project.manifest";
  _updateListener = null;
  _am = null;
  _updating = false;
  _canRetry = false;
  _canInstall = false;
  // use this for initialization
  init() {
    // Hot update is only available in Native build
    if (!cc.sys.isNative) {
      return;
    }
    this.reset();

    this._storagePath = "";
    this.file_version = "version.manifest";
    this.file_project = "project.manifest";

    this._storagePath =
      (jsb.fileUtils ? jsb.fileUtils.getWritablePath() : "/") + cc.vv.GLConfig.resPath;
    cc.log("Storage path for remote asset : " + this._storagePath);
  }

  onDestroy() {
    if (this._updateListener) {
      this._am.setEventCallback(null);
      this._updateListener = null;
    }
  }

  reset() {
    if (!cc.sys.isNative) {
      return;
    }
    this._updating = false;
    this._canRetry = false;
    this._canInstall = false;
  }

  setVerifyCallback(path, asset) {
    var compressed = asset.compressed;

    console.log("_____path = " + path);
    console.log("_____asset = " + JSON.stringify(asset));
    var data = jsb.fileUtils.getDataFromFile(path);
    var curMD5 = window.Md51(data);
    // console.log("_____data = " + data);
    // console.log("_____curMD5 = " + curMD5);
    if (curMD5 == asset.md5) {
      return true;
    } else {
      return false;
    }
    if (compressed) {
      //panel.info.string = "Verification passed : " + relativePath;
      return true;
    } else {
      // panel.info.string = "Verification passed : " + relativePath + ' (' + expectedMD5 + ')';
      return true;
    }
  }

  versionCompareHandle(versionA, versionB) {
    cc.log(
      "JS Custom Version Compare: version A is " +
      versionA +
      ", version B is " +
      versionB
    );
    if (!versionA) {
      return -1;
    }
    var index_local = versionA.lastIndexOf(".");
    var core_local = versionA.substring(0, index_local);
    var index_remote = versionB.lastIndexOf(".");
    var core_remote = versionB.substring(0, index_remote);
    console.log("--------core_local:" + core_local);
    console.log("--------core_remote:" + core_remote);

    this._canInstall = false;
    if (core_remote > core_local) {
      //大版本不相同;先暂时仅支持重新下载;
      console.log("---------can Install");
      this._canInstall = true;
    }
    var vA = versionA.split(".");
    var vB = versionB.split(".");
    for (var i = 0; i < vA.length; ++i) {
      var a = parseInt(vA[i]);
      var b = parseInt(vB[i] || 0);
      if (a === b) {
        continue;
      } else {
        return -1; //a - b;
      }
    }
    if (vB.length > vA.length) {
      return -1;
    } else {
      return 0;
    }
  }

  checkCb(event) {
    console.log("____--event = " + JSON.stringify(event));
    var str = "";
    var error = 0;
    switch (event.getEventCode()) {
      case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
        console.log("_____can Install = " + this._canInstall);
        var _version1 = "0.1.1";
        var _version2 = this._am.getRemoteManifest().getVersion();
        if (this._canInstall) {
          cc.vv.eventCustom.emit("hotUpError", this.errorCode.NEED_INSTALL)
        } else {
          cc.vv.eventCustom.emit(
            "hotUpError",
            this.errorCode.NEED_UPDATE,
            _version1,
            _version2
          );
        }
        break;
      case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
      case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
        cc.vv.eventCustom.emit(
          "hotUpError",
          this.errorCode.FAIL_DOWMLOAD_MANIFEST
        );

        break;
      case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
        var _version = this._am.getLocalManifest().getVersion();
        console.log("______________version = " + _version);
        cc.vv.GLConfig.setLocalVersion(_version);

        cc.vv.eventCustom.emit("hotUpError", this.errorCode.ALREADY_UP_TO_DATE);
        break;
      case jsb.EventAssetsManager.NEW_VERSION_FOUND:
        // str = 'New version found, please try to update.';
        console.log("_____can Install = " + this._canInstall);
        var _version1 = this._am.getLocalManifest().getVersion();
        var _version2 = this._am.getRemoteManifest().getVersion();
        if (this._canInstall) {
          cc.vv.eventCustom.emit("hotUpError", this.errorCode.NEED_INSTALL);
        } else {
          cc.vv.eventCustom.emit(
            "hotUpError",
            this.errorCode.NEED_UPDATE,
            _version1,
            _version2
          );
        }

        break;
      default:
        //cc.vv.eventCustom.emit("hotUpError", this.errorCode.ERROR_OTHER);
        return;
    }

    this._am.setEventCallback(null);
    //this._checkListener = null;
  }

  getSize(size) {
    var _size = "";
    var _M = 1024 * 1024;
    var _K = 1024;
    if (size > _M) {
      _size = (size / _M).toFixed(2) + "MB";
    } else if (size > _K) {
      _size = (size / _K).toFixed(2) + "KB";
    } else {
      _size = size + "B";
    }
    return _size;
  }

  updateCb(event) {
    console.log("___updateCb");
    var needRestart = false;
    var failed = false;

    switch (event.getEventCode()) {
      case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
        //  this.UIPanel.info.string = 'No local manifest file found, hot update skipped.';
        failed = true;
        cc.vv.eventCustom.emit(
          "hotUpError",
          this.errorCode.ERROR_NO_LOCAL_MANIFEST
        );
        break;
      case jsb.EventAssetsManager.UPDATE_PROGRESSION:
        // this.UIPanel.byteProgress.progress = event.getPercent();
        //this.UIPanel.fileProgress.progress = event.getPercentByFile();

        //this.UIPanel.fileLabel.string = event.getDownloadedFiles() + ' / ' + event.getTotalFiles();
        //this.UIPanel.byteLabel.string = event.getDownloadedBytes() + ' / ' + event.getTotalBytes();

        var msg = event.getMessage();
        if (msg) {
          console.log("______files = " + msg);
          //  this.UIPanel.info.string = 'Updated file: ' + msg;
          // cc.log(event.getPercent()/100 + '% : ' + msg);
        }
        // this.UIPanel.updateProgress(3, event.getPercent(), msg);
        // var _per = event.getPercent();
        // var _down = event.getDownloadedBytes();
        // var _total = event.getTotalBytes();
        // var _msg = event.getMessage();
        // var _per1 = event.getPercentByFile();
        // console.log("__________event = " + event);
        // console.log("__________per = " + _per);
        // console.log("__________per1 = " + _per1);
        // console.log("__________down = " + _down);
        // console.log("__________total = " + _total);
        // console.log("___________msg = " + _msg);

        var _totalSize = this.getSize(event.getTotalBytes());
        console.log("___________totalSize = " + _totalSize);

        cc.vv.eventCustom.emit(
          "hotUpError",
          this.errorCode.UPDATE_PROGRESSION,
          event.getPercent(),
          _totalSize
        );
        break;
      case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
      case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
        //this.UIPanel.info.string = 'Fail to download manifest file, hot update skipped.';
        failed = true;
        cc.vv.eventCustom.emit(
          "hotUpError",
          this.errorCode.FAIL_DOWMLOAD_MANIFEST
        );
      case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
        //this.UIPanel.info.string = 'Already up to date with the latest remote version.';

        failed = true;
        cc.vv.eventCustom.emit("hotUpError", this.errorCode.ALREADY_UP_TO_DATE);
        break;
      case jsb.EventAssetsManager.UPDATE_FINISHED:
        //this.UIPanel.info.string = 'Update finished. ' + event.getMessage();
        failed = true;

        needRestart = true;
        cc.vv.eventCustom.emit("hotUpError", this.errorCode.UPDATE_FINISHED);
        break;
      case jsb.EventAssetsManager.UPDATE_FAILED: //更新失败
        this._updating = false;
        this._canRetry = true;
        cc.vv.eventCustom.emit(
          "hotUpError",
          this.errorCode.UPDATE_FAILED,
          event.getMessage()
        );
        break;
      case jsb.EventAssetsManager.ERROR_UPDATING: //下载失败
        // this._updating = false;
        // this._canRetry = true;
        //this.UIPanel.info.string = 'Asset update error: ' + event.getAssetId() + ', ' + event.getMessage();
        cc.vv.eventCustom.emit("hotUpError", this.errorCode.ERROR_UPDATING);
        break;
      case jsb.EventAssetsManager.ERROR_DECOMPRESS:
        cc.vv.eventCustom.emit("hotUpError", this.errorCode.ERROR_DECOMPRESS);
        break;
      default:
        // cc.vv.eventCustom.emit("hotUpError", this.errorCode.ERROR_OTHER);
        break;
    }

    if (failed) {
      this._am.setEventCallback(null);
      this._updateListener = null;
      this._updating = false;
    }

    if (needRestart) {
      this._am.setEventCallback(null);
      this._updateListener = null;
      // Prepend the manifest's search path
      var searchPaths = jsb.fileUtils.getSearchPaths();
      //var newPaths = this._am.getLocalManifest().getSearchPaths();
      //console.log("____________newPaths" + JSON.stringify(newPaths));
      //Array.prototype.unshift.apply(searchPaths, newPaths);
      // This value will be retrieved and appended to the default search path during game startup,
      // please refer to samples/js-tests/main.js for detailed usage.
      // !!! Re-add the search paths in main.js is very important, otherwise, new scripts won't take effect.
      cc.sys.localStorage.setItem(
        "HotUpdateSearchPaths",
        JSON.stringify(searchPaths)
      );
      //jsb.fileUtils.setSearchPaths(searchPaths);

      var _version = this._am.getLocalManifest().getVersion();
      cc.vv.GLConfig.setLocalVersion(_version);

      cc.audioEngine.stopAll();
      console.log("________restart");
      cc.game.restart();
    }
  }

  // loadCustomManifest() {
  //   if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
  //     var manifest = new jsb.Manifest(customManifestStr, this._storagePath);
  //     this._am.loadLocalManifest(manifest, this._storagePath);
  //     //this.UIPanel.info.string = 'Using custom manifest';
  //   }
  // }

  retry() {
    console.log("_______retry1");
    if (!this._updating && this._canRetry) {
      this._canRetry = false;
      console.log("_______retry2");
      this._am.downloadFailedAssets();
    }
  }

  checkUpdate() {
    console.log("______checkUpdate1");

    if (!cc.sys.isNative) {
      cc.vv.eventCustom.emit("hotUpError", this.errorCode.ERROR_OTHER);
      return;
    }
    if (this._updating) {
      return;
    }
    console.log("______checkUpdate1__111_____2222");

    this._am = null;
    this._am = new jsb.AssetsManager("", this._storagePath);
    this._am.setVersionCompareHandle(this.versionCompareHandle.bind(this));
    //this._am.setVerifyCallback(this.setVerifyCallback.bind(this));

    if (cc.sys.os === cc.sys.OS_ANDROID) {
      this._am.setMaxConcurrentTask(2);
    }

    if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
      let _url = "http://" + cc.vv.GLConfig.hotUpdateURL + "/" + cc.vv.GLConfig.resPath + "/hall";
      console.log("____trmp _url = " + _url);
      let temp = this._storagePath + "/" + this.file_project;
      var file_manifest;
      if (!jsb.fileUtils.isFileExist(temp)) {
        file_manifest = jsb.fileUtils.getStringFromFile("res/project.manifest");
      } else {
        file_manifest = jsb.fileUtils.getStringFromFile(temp);
      }
      var _temp_manifest;
      if (file_manifest) {
        _temp_manifest = JSON.parse(file_manifest);
        let _version = _temp_manifest.version;
        _temp_manifest.packageUrl = _url + "/" + _version;
        _temp_manifest.remoteManifestUrl = _url + "/" + "project.manifest";
        _temp_manifest.remoteVersionUrl = _url + "/" + "version.manifest";
      } else {
        _temp_manifest = {};
        let _version = "0.1.1"
        _temp_manifest.packageUrl = _url + "/" + _version;
        _temp_manifest.remoteManifestUrl = _url + "/" + "project.manifest";
        _temp_manifest.remoteVersionUrl = _url + "/" + "version.manifest";
        let fullpath = this._storagePath + "/res/project.manifest";
        if (!jsb.fileUtils.isDirectoryExist(fullpath)) {
          jsb.fileUtils.createDirectory(fullpath);
        }
        let str = JSON.stringify(_temp_manifest);
        console.log(" hot str is  ", str)
        jsb.fileUtils.writeStringToFile(str, fullpath);
      }

      console.log("____trmp _url = 12345");
      //console.log("_______temp_manifest = " + _temp_manifest);

      var _manifest = JSON.stringify(_temp_manifest);

      let manifest = new jsb.Manifest(_manifest, this._storagePath + "/");
      //  console.log("______manifest1 = " + manifest);
      this._am.loadLocalManifest(manifest, this._storagePath);
    }

    if (
      !this._am.getLocalManifest() ||
      !this._am.getLocalManifest().isLoaded()
    ) {
      cc.vv.eventCustom.emit(
        "hotUpError",
        this.errorCode.ERROR_NO_LOCAL_MANIFEST
      );
      return;
    }

    console.log("______checkUpdate2");
    this._am.setEventCallback(this.checkCb.bind(this));
    this._am.checkUpdate();
    //this._updating = true;
  }

  hotUpdate() {
    if (!cc.sys.isNative) {
      return;
    }
    if (this._am && !this._updating) {
      this._am.setEventCallback(this.updateCb.bind(this));

      this._am.update();
      this._updating = true;
    }
  }

  removeHotUpdateDir() {
    console.log("____remove path=" + this._storagePath);
    // console.log("____remove path2=" + storage_path);
    jsb.fileUtils.removeDirectory(this._storagePath + "_temp");
    jsb.fileUtils.removeDirectory(this._storagePath);
    // jsb.fileUtils.removeDirectory(jsb.fileUtils.getWritablePath());
  }
  removeHotUpdateTempDir() {
    console.log("____remove path1=" + this._storagePath + "_temp");
    jsb.fileUtils.removeDirectory(this._storagePath + "_temp");
  }

  compareVersion(versionA, versionB) {
    var vA = versionA.split(".");
    var vB = versionB.split(".");
    for (var i = 0; i < vA.length; ++i) {
      var a = parseInt(vA[i]);
      var b = parseInt(vB[i] || 0);
      if (a === b) {
        continue;
      } else if (a > b) {
        return 1; //a - b;
      } else {
        return -1;
      }
    }
    return 0;
  }
  /*
   * 获取当前版本号。如果原生包版本号大于热更包版本号，删除热更资源
   *
   */
  getLocalVersion() {
    if (!cc.sys.isNative) {
      return;
    }

    //获取原生包配置文件
    let file_manifest = jsb.fileUtils.getStringFromFile("res/project.manifest");
    var ss = {
      version: ""
    };
    if (file_manifest) {
      ss = JSON.parse(file_manifest);
    }
    var _version = ss.version;
    console.log("____version = " + _version);

    //获取热更配置文件
    let temp = this._storagePath + "/" + "project.manifest";
    console.log("_______temp path =" + temp);
    if (jsb.fileUtils.isFileExist(temp)) {
      console.log("____getLocalVersion  222");
      var res_ss = {
        version: ""
      };
      var res_manifest = jsb.fileUtils.getStringFromFile(temp);

      if (res_manifest) {
        res_ss = JSON.parse(res_manifest);
      }

      if (res_ss.version) {
        console.log("____res_ss.version = " + res_ss.version);
        var sub = this.compareVersion(_version, res_ss.version);
        //var sub = parseFloat(_version) - parseFloat(res_ss.version);
        if (sub >= 0) {
          //删除
          console.log("____res_ss.version111111 = " + res_ss.version);
          this.removeHotUpdateDir();
        } else {
          _version = res_ss.version;
        }
      } else {
        //删除
        this.removeHotUpdateDir();
      }
    }

    // var _version = ss.version; //this._am.getLocalManifest().getVersion();
    console.log("_______version = " + _version);
    cc.vv.GLConfig.setLocalVersion(_version);
  }
}

export let hotUpdate: HotUpdate = new HotUpdate();
